1 module hip.game2d.tileworld; 2 public import hip.api.data.tilemap; 3 public import hip.component.physics; 4 public import hip.math.collision; 5 6 7 8 class TileWorld 9 { 10 IHipTilemap map; 11 ///Affects position 12 float constantGravity = 0; 13 ///Affects velocity 14 float gravity = 0; 15 16 BodyRectComponent[] dynamicBodies; 17 HipTileLayer[] collidibleLayers; 18 19 this(IHipTilemap map, float gravity = 0, float constantGravity = 0) 20 { 21 this.map = map; 22 this.gravity = gravity; 23 this.constantGravity = constantGravity; 24 } 25 26 private Rect[128] rectCache; 27 Rect[] getRectsOverlapping(HipTileLayer layer, in Rect input) @nogc 28 { 29 import hip.math.utils; 30 if(!layer.isInLayerBoundaries( 31 cast(int)input.x, cast(int)input.y, cast(int)input.w, cast(int)input.h 32 )) 33 return rectCache[0..0]; 34 35 uint tileW = map.tileWidth, tileH = map.tileHeight; 36 float x = input.x - layer.x; 37 float y = input.y - layer.y; 38 39 40 41 42 43 float inputTilesWidth = input.w / tileW; 44 float inputTilesHeight = input.h / tileH; 45 46 float i = x/tileW; 47 float j = y/tileH; 48 float i2 = ceil(min(i + inputTilesWidth, layer.columns)); 49 float j2 = ceil(min(j + inputTilesHeight, layer.rows - 1)); 50 51 52 float plusI = min(inputTilesWidth, 1); 53 float plusJ = min(inputTilesHeight, 1); 54 55 int lastI = -1; 56 int lastJ = -1; 57 58 int rects = 0; 59 for(; j < j2; j+= plusJ) 60 for(float _i = i; _i < i2; _i+= plusI) 61 { 62 if(_i < 0 || j < 0) 63 continue; 64 int ui = cast(int)_i; 65 int uj = cast(int)j; 66 67 if(ui == lastI && uj == lastJ) 68 continue; 69 lastI = ui; 70 lastJ = uj; 71 72 ushort tID = layer.checkedGetTile(ui, uj); 73 if(tID != 0) 74 { 75 rectCache[rects++] = Rect(layer.x + ui*tileW, layer.y + uj*tileH, tileW, tileH); 76 } 77 } 78 return rectCache[0..rects]; 79 } 80 81 void addDynamic(IComponentizable component) 82 { 83 auto comp = component.getComponent!BodyRectComponent; 84 assert(comp !is null, "No BodyRectComponent found"); 85 assert(comp.size.w != 0, "Can't have 0 width component"); 86 assert(comp.size.h != 0, "Can't have 0 height component"); 87 dynamicBodies~= comp; 88 } 89 90 void addCollidibleLayer(HipTileLayer layer) 91 { 92 collidibleLayers~= layer; 93 } 94 95 void update2(float dt) @nogc 96 { 97 import std.algorithm.sorting:sort; 98 struct DynamicRectCollision 99 { 100 Vector2 normal; 101 float time; 102 } 103 static DynamicRectCollision[128] colCache; 104 foreach(dynBody; dynamicBodies) 105 { 106 dynBody.velocity.y += gravity; 107 Rect bodyRec = dynBody.rect; 108 int z = 0; 109 110 foreach(HipTileLayer l; collidibleLayers) 111 for(int j = 0; j < l.rows; j++) 112 for(int i = 0; i < l.columns; i++) 113 { 114 if(l.getTile(i, j) != 0) 115 { 116 DynamicRectCollision col = void; 117 if(isDynamicRectOverlappingRect(bodyRec, dynBody.velocity, Rect(l.x + i*l.tileWidth, l.y+j*l.tileHeight, l.tileWidth, l.tileHeight), dt, col.normal, col.time)) 118 colCache[z++] = col; 119 } 120 } 121 if(z > 0) 122 foreach(col; sort!((DynamicRectCollision a, DynamicRectCollision b) => a.time < b.time)(colCache[0..z])) 123 resolveDynamicRectOverlappingRect(col.normal, dynBody.velocity, col.time); 124 dynBody.position+= dynBody.velocity* dt; 125 } 126 } 127 128 void update(float dt) @nogc 129 { 130 import std.algorithm.sorting:sort; 131 struct DynamicRectCollision 132 { 133 Vector2 normal; 134 float time; 135 } 136 static DynamicRectCollision[128] colCache; 137 foreach(dynBody; dynamicBodies) 138 { 139 dynBody.velocity.y += gravity; 140 Rect bodyRec = dynBody.rect; 141 int i = 0; 142 143 foreach(l; collidibleLayers) 144 foreach(const ref rect; getRectsOverlapping(l, dynBody.expandedRectVel)) 145 { 146 DynamicRectCollision col = void; 147 if(isDynamicRectOverlappingRect(bodyRec, dynBody.velocity, rect, dt, col.normal, col.time)) 148 colCache[i++] = col; 149 } 150 if(i > 0) 151 foreach(col; sort!((DynamicRectCollision a, DynamicRectCollision b) => a.time < b.time)(colCache[0..i])) 152 resolveDynamicRectOverlappingRect(col.normal, dynBody.velocity, col.time); 153 dynBody.position+= dynBody.velocity* dt; 154 } 155 } 156 }